 /*   
 * Project: OSMP
 * FileName: Modbus.java
 * version: V1.0
 */
package com.jwkj.scollect.collector.zknh;

 import java.util.Calendar;
import java.util.Date;

 /**
  * Description:
  * @author: wangkaiping
  * @date: 2018年3月6日 下午4:11:13上午10:51:30
  */
 public class Modbus {
     private boolean IsValid;
       private int Code;
       private int Address;
       private short[] Values;
       private Date Time;

       public Modbus(byte[] byts)
         throws IllegalAccessException
       {
         if (byts == null)
           throw new NullPointerException();
         if (byts.length < 5) {
           throw new IllegalAccessException("非modbus数据帧");
         }
         CRC crc = CRC16(byts, byts.length - 2);
         this.IsValid = ((crc.High == byts[(byts.length - 2)]) && (crc.low == byts[(byts.length - 1)]));
         if (this.IsValid) {
           this.Address = byts[0];
           this.Code = byts[1];
           this.Values = new short[byts[2] / 2];
           for (int i = 3; i < this.Values.length; i++) {
             this.Values[i] = ((short)(byts[(i * 2 + 3)] << 8 | byts[(i * 2 + 4)] & 0xFF));
           }
           Calendar c = Calendar.getInstance();
           int y = byts[3] == -1 ? 1 : 2000 + (byts[3] & 0xFF);
           int M = byts[4] == -1 ? 0 : byts[4] & 0xFF;
           int d = byts[5] == -1 ? 1 : byts[5] & 0xFF;
           int H = byts[6] == -1 ? 0 : byts[6] & 0xFF;
           int m = byts[7] == -1 ? 0 : byts[7] & 0xFF;
           int s = byts[8] == -1 ? 0 : byts[8] & 0xFF;
           c.set(y, M-1, d, H, m, s);
           this.Time = c.getTime();
         }
       }

       /**
        * 读取实时数据指令
        * @param address 设备地址
        * @param index 起始寄存器
        * @param size 寄存器数量
        * @return
        */
       public static byte[] get04Cmd(int address, int index, int size)
       {
         byte[] cmd = { (byte)address, 4, 0, (byte)index, 0, (byte)size, -1, -1 };
         CRC crc = CRC16(cmd, cmd.length - 2);
         cmd[(cmd.length - 2)] = crc.High;
         cmd[(cmd.length - 1)] = crc.low;
         return cmd;
       }

       /**
        * 读取历史数据指令
        * @param address 设备地址
        * @param offset 历史数据偏移（0代表最近一条历史数据，1代表上一条，2代表上上条）
        * @return
        */
       public static byte[] get41Cmd(int address, int offset) {
         byte HH = (byte)(offset >> 24 & 0xFF);
         byte HL = (byte)(offset >> 16 & 0xFF);
         byte H = (byte)(offset >> 8 & 0xFF);
         byte L = (byte)(offset & 0xFF);
         byte[] cmd = { (byte)address, 65, HH, HL, H, L, -1, -1 };
         CRC crc = CRC16(cmd, cmd.length - 2);
         cmd[(cmd.length - 2)] = crc.High;
         cmd[(cmd.length - 1)] = crc.low;
         return cmd;
       }

       public int Address() {
         return this.Address;
       }

       public int Code() {
         return this.Code;
       }

       public boolean IsValid()
       {
         return this.IsValid;
       }

       public short getValue(int index) {
         return this.Values[index];
       }

       public Date getTime() {
         return this.Time;
       }

       private static CRC CRC16(byte[] byts, int len)
       {
         CRC crc = new CRC();

         int CRC = 65535;
         for (int i = 0; i < len; i++) {
           CRC ^= byts[i] & 0xFF;
           for (int Temp = 0; Temp < 8; Temp++) {
             if ((CRC & 0x1) == 1)
               CRC = CRC >> 1 ^ 0xA001;
             else
               CRC >>= 1;
           }
         }
         crc.High = ((byte)(CRC & 0xFF));
         crc.low = ((byte)((CRC & 0xFF00) >> 8));
         return crc;
       }
 }
